#include <iostream>
#include <Eigen\Dense>
#include <Eigen/Sparse>

#include"traitDemo.h"

#include <array>
#include <vector>
using namespace std;
using namespace Eigen;



void basicDemo()
{

    printf("hello!\n");
    {
    MatrixXd m = MatrixXd::Random(3, 3);
    m = (m + MatrixXd::Constant(3, 3, 1.2)) * 50;
    cout << "m =" << endl << m << "\n\n";
    VectorXd v(3);
    v << 1, 2, 3;
    cout << "m * v =" << endl << m * v << endl;
    }

    cout<< "\n\n\t------\n\n" ;

    {
    Matrix2d a;
    a << 1, 2,
        3, 4;
    MatrixXd b(2, 2);
    b << 2, 3,
        1, 4;
    cout << "a + b =\n" << a + b << "\n\n";
    cout << "a - b =\n" << a - b << "\n\n";
    cout << "Doing a += b;" << endl;
    a += b;
    cout << "Now a =\n" << a << "\n\n";
    cout << "a^T=  \n" << a.transpose() << "\n\n";
    cout << "a*b= \n" << a*b << "\n\n";

    Vector3d v(1, 2, 3);
    Vector3d w(1, 0, 0);
    cout << "-v + w - v =\n" << -v + w - v << "\n\n";
    cout << v << "\n\n";
    cout << v.transpose() << "\n\n";
    }

    cout << "===============next section===============================================\n\n" ;

 //   system("pause");

    //====================================矩阵/向量乘法========================================
    Matrix2d m4;
    m4 << 1, 2,3, 4;
    Vector2d u6(-1, 1), v6(2, 0);
    RowVector2d rowV(1,2);

    cout << "m4 =\n" << m4 << "\n\n";
    cout << "u6 =\n" << u6 << "\n\n";
    cout << "u6.transpose() =\n" << u6.transpose() << "\n\n";
    cout << "rowV =\n" << rowV << "\n\n";

    cout << "Here is m4*m4:\n" << m4 * m4 << endl;
    //矩阵-矩阵
    cout << "Here is m4*u6:\n" << m4 * u6 << endl;
    //矩阵-向量
    cout << "Here is u6^T*m4:\n" << u6.transpose()*m4 << endl;
    //向量-矩阵
    cout << "Here is u6^T*v6:\n" << u6.transpose()*v6 << endl;
    //向量-向量
    cout << "Here is u6*v6^T:\n" << u6 * v6.transpose() << endl;
    //向量-向量
    cout << "===============next section===============================================\n\n" ;


    //==============================转置，共轭,伴随以及逆矩阵=======================================
    //定义2-by-2随机矩阵
    MatrixXcf a3 = MatrixXcf::Random(2, 2);
    cout << "Here is the matrix a3\n" << a3 << endl;
    //矩阵a3

    cout << "Here is the matrix a3^T\n" << a3.transpose() << endl;
    //a3的转置

    cout << "Here is the matrix a3^H\n" << a3.conjugate() << endl;
    //a3的共轭

    cout << "Here is the adjoint of a3\n" <<a3.adjoint() << endl;
    //a3的伴随矩阵

    cout << "Here is the matrix a3^{-1}\n" << a3.inverse() << endl;
    //a3的逆

    cout << "===============next section===============================================\n\n" ;


    //=====================================点乘/叉乘============================================
    Vector3d v7(1, 2, 3);Vector3d w7(0, 1, 2);
    cout << "Dot product: " << v7.dot(w7) << endl;
    //向量点乘

    cout << "Cross product:\n" << v7.cross(w7) << endl;
    //向量叉乘
   cout << "===============next section===============================================\n\n" ;


    //==================================== 其他功能==============================================
    Matrix3d m5;m5 << 1, 2, 3,1, 2, 1,0, 2, 4;

    cout << "Here is m5.determinant():   " << m5.determinant() << endl;
    // 行列式

    cout << "Here is m5.sum():           " << m5.sum() << endl;
    //所有元素之和

    cout << "Here is m5.prod():          " << m5.prod() << endl;
    //所有元素之积

    cout << "Here is m5.mean():          " << m5.mean() << endl;
    //元素的平均数

    cout << "Here is m5.minCoeff():      " << m5.minCoeff() << endl;
    //最小元素

    cout << "Here is m5.maxCoeff():      " << m5.maxCoeff() << endl;
    //最大元素

    cout << "Here is m5.trace():         " << m5.trace() << endl;
    //迹（对角元素之和)

    cout << "===============next section===============================================\n\n" ;


    //==================================== 矩阵改变大小============================================
    /*
当前矩阵的行数、列数、大小可以通过rows()，cols()和size()来获取，
上面用“=”改变矩阵大小的方式除此之外，
对于动态矩阵可以通过resize()函数来动态修改矩阵的大小.
需注意：
(1) 固定大小的矩阵是不能使用resize（）来修改矩阵的大小；
(2) resize（）函数会析构掉原来的数据，因此调用resize（）函数之后将不能保证元素的值不改变。
*/

    MatrixXd m6(3,3);
    cout << " the number of rows " << m6.rows() << endl;
    cout << " the number of cols " << m6.cols() << endl;
    cout << " the number of size " << m6.size() << endl;
    m6.resize(4, 5);
    cout << "resize(4, 5)" << endl;
    cout << " the number of rows " << m6.rows() << endl;
    cout << " the number of cols " << m6.cols() << endl;
    cout << " the number of size " << m6.size() << endl;


}

typedef Eigen::SparseMatrix<double> SpMat; // declares a column-major sparse matrix type of double
typedef Eigen::Triplet<double> T;

void buildProblem(std::vector<T>& coefficients, Eigen::VectorXd& b, int n)
{}
void saveAsBitmap(const Eigen::VectorXd& x, int n, const char* filename)
{}

//SparseMatrix  SparseVector 稀疏矩阵
void sparseDemo()
{
    auto fileName="d:/spareDemo.bmp";

    int n = 300;  // size of the image
    int m = n*n;  // number of unknowns (=number of pixels)

    // Assembly:
    std::vector<T> coefficients;            // list of non-zeros coefficients
    Eigen::VectorXd b(m);                   // the right hand side-vector resulting from the constraints
    buildProblem(coefficients, b, n);

    SpMat A(m,m);
    A.setFromTriplets(coefficients.begin(), coefficients.end());

    // Solving:
    Eigen::SimplicialCholesky<SpMat> chol(A);  // performs a Cholesky factorization of A
    Eigen::VectorXd x = chol.solve(b);         // use the factorization to solve for the given right hand side

    // Export the result to a file:
    saveAsBitmap(x, n, fileName);

}

template<typename T> struct iters_before_test { enum { ret = 8 }; };
template<> struct iters_before_test<double> { enum { ret = 16 }; };
template<typename Real> void fun()
{
    enum { packetSize = Eigen::internal::packet_traits<Real>::size }; // number of reals in a Packet
    typedef Eigen::Array<Real, packetSize, 1> Packet; // wrap a Packet as a vector

    enum { iters_before_test = iters_before_test<Real>::ret };

    int max_iter = (max_iter / iters_before_test) * iters_before_test;

    typedef Eigen::Matrix<int, packetSize, 1> Packeti;

   auto total_iter = iters_before_test * packetSize;

    typedef Eigen::Matrix<int, packetSize, 1> Packeti;
   Packeti pix_iter = Packeti::Zero(), // number of iteration per pixel in the packet
       pix_dont_diverge; // whether or not each pixel has already diverged

    int t1=iters_before_test;
   auto tmp= t1 * pix_dont_diverge;
   pix_iter*1;


   cout<< "\n total_iter \t"<< total_iter<<"\n ";
    cout<< " max_iter \t"<< max_iter<<"\n\n ";
}

void arrayDemo()
{
    cout <<"\n\n ";

    std::array<int, 5> a0 = {0, 1, 2, 3, 4};          //正确
    std::array<int, 5> a1 = a0;                       //正确

    std::cout << a1.front() << " " << a1.at(1) << " " << a1[2] << " " << *(a1.data() + 3) << " " << a1.back() << std::endl;

    std::array<int, 5>::iterator iter;
    for (iter = a1.begin(); iter != a1.end(); ++iter)
    std::cout << *iter << " ";
    cout <<"\n\n ";

    std::array<int, 5>::reverse_iterator riter;
    for (riter = a1.rbegin(); riter != a1.rend(); ++riter)
    std::cout << *riter << " ";
    cout <<"\n\n ";

    cout <<"std::array<int, 4>::iterator:\n ";
    std::array<int, 4>::iterator iter4;
    for (iter4 = a1.begin(); iter4 != a1.end(); ++iter4)
    std::cout << *iter4 << " ";
cout <<"\n\n ";

cout <<"反转a1 \n ";
    std::reverse(a1.begin(), a1.end());                           //反转a1
    for (std::array<int, 5>::iterator iter = a1.begin(); iter != a1.end(); ++iter)
    std::cout << *iter << " ";
cout <<"\n\n ";

    cout <<"反转a1的内容拷贝到a2 \n ";
    std::array<int, 5> a2;
    std::reverse_copy(a1.begin(), a1.end(), a2.begin());          //反转a1的内容拷贝到a2
    for (size_t i = 0; i < a2.size(); ++i)
    std::cout << a2[i] << " ";
    std::cout << std::endl;

    cout <<"\n\n ";


   auto demo1= Enum<animals>{animals::cat, "animals::cat"};
    auto demo2= Enum<animals>{animals::dog};
   auto demo3=animalsStr[2];
    cout <<demo1.name<<"\n ";
    cout <<demo2.name<<"\n ";
    cout <<demo3.name<<"\n ";

    cout <<"\n\n ";
}

void find_if_Demo()
{
    cout<< "\n std::find_if  \n\n" ;
    vector<int> lst;
    lst.push_back(10);
    lst.push_back(20);
    lst.push_back(30);
    auto it = std::find_if(lst.begin(), lst.end(), [  ](int value) {
        cout<< "\n---------- value : " << value;
        return value == 10;
    }); // 查找list中是否有元素“10”

    if (it != lst.end()) { // 找到了
    cout << "\n---------1  yes \n ";
    } else { // 没找到
    cout << "---------1 no \n";
    }

    auto it2 = std::find_if(lst.begin(), lst.end(), [ = ](int value) {
        cout << "\n---------- value2 : " << value;
        return value == 40;
    }); // 查找list中是否有元素“40”

    if (it2 != lst.end()) { // 找到了
    cout << "\n---------2 yes \n";
    } else { // 没找到
    cout << "\n---------2 no \n";
    }
}

int main()
{
  //  basicDemo();
 //   traitDemo();
   // sparseDemo();


    cout <<"\n enum to_string demo : "  << _to_string(animals::dog, animalsStr);
    cout <<"\n enum to_string demo : "  << _to_string(cat, AnimalsStr);

    cout <<"\n enum to_string demo : "  << to_string(animals::dog);

    Enum1 a1(animals::dog);
   cout <<"\n\n a1 : " << a1.toString();

   // arrayDemo();

   fun<double>();


   cout <<"\n\n ";



    cout <<"\n\n ";
    return 0;
}




